package org.aurora.framework.boot.rpc.dubbo.aop;

import jakarta.validation.Valid;
import jakarta.validation.ValidationException;
import org.aopalliance.intercept.MethodInvocation;
import org.aurora.framework.boot.common.aop.AbstractAnnotationMethodInterceptor;
import org.aurora.framework.boot.common.exception.ServiceException;
import org.aurora.framework.boot.common.exception.SystemException;
import org.aurora.framework.boot.common.validator.BeanValidator;
import org.aurora.framework.boot.rpc.dubbo.annotation.Facade;
import org.aurora.framework.boot.common.rpc.response.BaseResponse;
import org.aurora.framework.boot.common.rpc.response.ResponseCode;
import org.aurora.framework.boot.common.rpc.response.RpcResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.NonNull;
import org.springframework.validation.annotation.Validated;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Objects;

/**
 * FacadeValidatorMethodInterceptor
 * <pre>
 * description:
 * create date: 2025-03-23 00:10:01
 * </pre>
 *
 * @author cao.yong
 */
public class FacadeValidatorMethodInterceptor extends AbstractAnnotationMethodInterceptor<Facade> {

    private static final Logger LOGGER = LoggerFactory.getLogger(FacadeValidatorMethodInterceptor.class);

    @Override
    public Object invoke(@NonNull MethodInvocation invocation) {
        Method method = invocation.getMethod();
        Facade anFacade = method.getAnnotation(Facade.class);
        Parameter[] parameters = method.getParameters();
        Object[] args = invocation.getArguments();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Valid anValid = parameter.getAnnotation(Valid.class);
            boolean validate = Objects.nonNull(anValid);
            if (!validate) {
                Validated anValidated = parameter.getAnnotation(Validated.class);
                validate = Objects.nonNull(anValidated);
            }
            if (validate) {
                try {
                    BeanValidator.validate(args[i], anFacade.groups());
                } catch (ValidationException ve) {
                    return failureResponse(method.getReturnType(), ve);
                }
            }
        }
        try {
            return invocation.proceed();
        } catch (Throwable e) {
            LOGGER.info("execute method:{}, ex: {}", method.getName(), e.getMessage());
            return failureResponse(method.getReturnType(), e);
        }
    }

    private Object failureResponse(Class<?> returnType, Throwable e) {
        if (RpcResponse.class.isAssignableFrom(returnType)) {
            if (e instanceof ValidationException) {
                return new BaseResponse(false, ResponseCode.ILLEGAL_ARGUMENT.getValue(), e.getMessage());
            } else if (e instanceof ServiceException se) {
                return new BaseResponse(false, ResponseCode.SERVICE_ERROR.getValue(), se.getReason().toString());
            } else if (e instanceof SystemException se) {
                return new BaseResponse(false, ResponseCode.SYSTEM_ERROR.getValue(), se.getReason().toString());
            } else {
                return new BaseResponse(false, ResponseCode.SYSTEM_ERROR.getValue(), e.getMessage());
            }
        }
        return null;
    }
}
